import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


public class FifteenPuzzle extends JFrame implements KeyListener, Runnable , Game {

	int[][] board = new int[4][4];
	int[] emptySquare = new int[2];
	int[] selectedSquare = new int[2];
	Thread mainThread;
	
	// This is the main method, it starts the entire program
	public static void main(String args[]) {
		FifteenPuzzle p = new FifteenPuzzle();
		p.resize(1024, 820);
		p.setVisible(true);
		p.setResizable(false);
		p.addKeyListener(p);
	} // end main method
	
	public FifteenPuzzle() {
		init();
	} // end default constructor
	
	// This method INITizializes everything
	public void init() {
		assignSquares();
		mainThread = new Thread(this);
		mainThread.start();
	} // end init method
	
	// This assigns values to squares
	public void assignSquares() {
		for(int i = 0; i < 16; i++)
			board[i/4][i%4] = 16-i;
		emptySquare[0] = 0;
		emptySquare[1] = 0;
		selectedSquare[0] = 0;
		selectedSquare[1] = 0;
		board[emptySquare[0]][emptySquare[1]] = -1;
	} // end assignSquares method
	
	// This method checks if the 15 puzzle is completed
	public boolean check() {
		for(int i = 0; i < 15; i++) {
			if(board[i/4][i%4] != i + 1)
				return false;
		} // end for
		return true;
	} // end check method
	
	// This waits for a key to be pressed and then does the appropriate action
	public void keyPressed(KeyEvent e) {
		// If D or the right arrow key is pressed, it moves the selected 
		// square right one
		if(e.getKeyCode() == e.VK_D || e.getKeyCode() == e.VK_RIGHT) 
			if(selectedSquare[1] < 3)
				selectedSquare[1]++;
		
		// If A or the left arrow key is pressed, it moves the selected 
		// square left one
		if(e.getKeyCode() == e.VK_A || e.getKeyCode() == e.VK_LEFT) 
			if(selectedSquare[1] > 0)
				selectedSquare[1]--;			
		
		// If S or the down arrow key is pressed, it moves the selected 
		// square down one
		if(e.getKeyCode() == e.VK_S || e.getKeyCode() == e.VK_DOWN)
			if(selectedSquare[0] < 3)
				selectedSquare[0]++;	
		
		// If W or the up arrow key is pressed, it moves the selected 
		// square up one
		if(e.getKeyCode() == e.VK_W || e.getKeyCode() == e.VK_UP) 
			if(selectedSquare[0] > 0)
				selectedSquare[0]--;	
		
		// If the space bar is pressed it shifts the entire row or column
		// over to fill in the empty space
		if(e.getKeyCode() == e.VK_SPACE) {
			if(selectedSquare[0] == emptySquare[0] && selectedSquare[1] == emptySquare[1])
				return;
			
			if(selectedSquare[0] == emptySquare[0]) {
				while(selectedSquare[1] > emptySquare[1]) 
					board[emptySquare[0]][emptySquare[1]] = board[emptySquare[0]][++emptySquare[1]];	
				while(selectedSquare[1] < emptySquare[1]) 
					board[emptySquare[0]][emptySquare[1]] = board[emptySquare[0]][--emptySquare[1]];	
			} // end if
			
			if(selectedSquare[1] == emptySquare[1]) {
				while(selectedSquare[0] > emptySquare[0]) 
					board[emptySquare[0]][emptySquare[1]] = board[++emptySquare[0]][emptySquare[1]];
				while(selectedSquare[0] < emptySquare[0]) 
					board[emptySquare[0]][emptySquare[1]] = board[--emptySquare[0]][emptySquare[1]];	
			} // end if
			
			board[emptySquare[0]][emptySquare[1]] = -1;
		} // end if
		repaint();
	} // end keyPressed method
	
	// This is an alternate key scheme which I choose not to use (but may be 
	// used at a later time
/*	public void keyPressed(KeyEvent e) {

		if(e.getKeyCode() == e.VK_D || e.getKeyCode() == e.VK_RIGHT) {
			if(emptySquare[1] + 1 > 3)
				return;
			board[emptySquare[0]][emptySquare[1]] = board[emptySquare[0]][emptySquare[1]+1];
			board[emptySquare[0]][emptySquare[1]+1] = -1;
			emptySquare[1]++;                                                                          
			                                                                            
		} 

		if(e.getKeyCode() == e.VK_S || e.getKeyCode() == e.VK_DOWN) {
			if(emptySquare[0] + 1 > 3)
				return;
			board[emptySquare[0]][emptySquare[1]] = board[emptySquare[0]+1][emptySquare[1]];
			board[emptySquare[0]+1][emptySquare[1]] = -1;
			emptySquare[0]++;
		} 

		if(e.getKeyCode() == e.VK_W || e.getKeyCode() == e.VK_UP) {
			if(emptySquare[0] - 1 < 0)
				return;
			board[emptySquare[0]][emptySquare[1]] = board[emptySquare[0]-1][emptySquare[1]];
			board[emptySquare[0]-1][emptySquare[1]] = -1;
			emptySquare[0]--;
		} 

		if(e.getKeyCode() == e.VK_A || e.getKeyCode() == e.VK_LEFT) {
			if(emptySquare[1] - 1 < 0)
				return;
			board[emptySquare[0]][emptySquare[1]] = board[emptySquare[0]][emptySquare[1]-1];
			board[emptySquare[0]][emptySquare[1]-1] = -1;
			emptySquare[1]--;   
		}
			
		repaint();
	}*/

	// This paints the screen with the appropriate strings
	public void paint(Graphics g) {
		Font f = new Font("Times", Font.PLAIN, 64);
		g.setFont(f);
		g.clearRect(0, 0, 1024, 820);
		for(int i = 0; i < 4; i++) {
			for(int j = 0; j < 4; j++) {
				if(i == selectedSquare[1] && j == selectedSquare[0])
					g.drawRect(i*100 + 300, j*100 + 180, 100, 100);
				if(board[i][j] != -1)
					g.drawString(board[i][j] + "", (j + 1)*100 + 200, (i + 1)*100 + 180);
			} // end for
		} // end for
	} // end paint method

	
	// This runs the program until the puzzle is finished and then quits
	public void run() {
		while(true) 
			if(check())
				System.exit(0);
	} // end run method

	// Unused methods
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub
		
	}

	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub
		
	}

	public void getInfo() {
		
	}
}
